package only.my.railgunys.artifact.calc;

import only.my.railgunys.artifact.ArtifactSub;
import only.my.railgunys.artifact.UpgradeSubStatFunction;
import only.my.railgunys.bean.db.PossibleFinalForm;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

public class SubStatRollCalc {
    public static double[] flatHP= {209,239,269,298.75};
    public static double[] flatATK= {14,16,18,19.45};
    public static double[] flatDEF= {16,19,21,23.15};
    public static double[] percentATK= {4.1,4.7,5.3,5.83};
    public static double[] percentHP= {4.1,4.7,5.3,5.83};
    public static double[] percentDEF= {5.1,5.8,6.6,7.29};
    public static double[] elementalMastery= {16,19,21,23.31};
    public static double[] energyRecharge= {4.5,5.2,5.8,6.48};
    public static double[] critRate= {2.7,3.1,3.5,3.89};
    public static double[] critDamage= {5.4,6.2,7,7.77};



    static List<PossibleFinalForm> upgradeArtifact(PossibleFinalForm possibleFinalForm, ArtifactSub[] subs) {
        List<PossibleFinalForm> possibleFinalForms = upOnce(possibleFinalForm, subs);
        int level = possibleFinalForms.get(0).getLevel();
        do{
            level+=4;
            possibleFinalForms = possibleFinalForms.stream()
                    .map(pff -> upOnce(pff, subs))
                    .flatMap(Collection::stream)
                    .collect(Collectors.toList());
        }while (level>= 20);

        return possibleFinalForms;
    }
    private static List<PossibleFinalForm> upOnce(PossibleFinalForm possibleFinalForm ,ArtifactSub[] subs){
        List<PossibleFinalForm> list = new ArrayList<>(6);
        int level = possibleFinalForm.getLevel();

        possibleFinalForm.setLevel(Math.min(level+4,20));
        for (ArtifactSub sub : subs) {
            List<PossibleFinalForm> upOneSubStat = sub.getPossibleUpgradeFunction().up(possibleFinalForm.copy());
            list.addAll(upOneSubStat);
        }
        return list;

    }

    public static List<PossibleFinalForm> up(PossibleFinalForm possibleFinalForm, double[] subStatusValues, UpgradeSubStatFunction function){
        List<PossibleFinalForm> list = getPossibleFinalForms(possibleFinalForm);
        upTotalList(function,subStatusValues,list);
        return list;
    }

    private static void upTotalList(UpgradeSubStatFunction function, double[] subStatusValues, List<PossibleFinalForm> list) {
        for (int i = 0; i < 4; i++) {
            function.upSubStat(list.get(i), subStatusValues[i]);
        }
    }

    private static List<PossibleFinalForm> getPossibleFinalForms(PossibleFinalForm possibleFinalForm) {
        List<PossibleFinalForm> list = new ArrayList<>();
        PossibleFinalForm copy1 = possibleFinalForm.copy();
        PossibleFinalForm copy2 = possibleFinalForm.copy();
        PossibleFinalForm copy3 = possibleFinalForm.copy();
        PossibleFinalForm copy4 = possibleFinalForm.copy();
        list.add(copy1);
        list.add(copy2);
        list.add(copy3);
        list.add(copy4);
        return list;
    }

    public static List<PossibleFinalForm> upFlatHp(PossibleFinalForm possibleFinalForm){
        return up(possibleFinalForm, flatHP,(a, b)->a.setFlatHP(a.getFlatHP()+b));
    }

    public static List<PossibleFinalForm> upFlatATK(PossibleFinalForm possibleFinalForm){
        return up(possibleFinalForm,flatATK,(a,b)->a.setFlatATK(a.getFlatATK()+b));
    }

    public static List<PossibleFinalForm> upFlatDEF(PossibleFinalForm possibleFinalForm){
        return up(possibleFinalForm,flatDEF,(a,b)->a.setFlatDEF(a.getFlatDEF()+b));
    }

    public static List<PossibleFinalForm> upPercentHP(PossibleFinalForm possibleFinalForm){
        return up(possibleFinalForm,percentHP,(a,b)->a.setPercentHP(a.getPercentHP()+b));
    }

    public static List<PossibleFinalForm> upPercentATK(PossibleFinalForm possibleFinalForm){
        return up(possibleFinalForm,percentATK,(a,b)->a.setPercentATK(a.getPercentATK()+b));
    }

    public static List<PossibleFinalForm> upPercentDEF(PossibleFinalForm possibleFinalForm){
        return up(possibleFinalForm,percentDEF,(a,b)->a.setPercentDEF(a.getPercentDEF()+b));
    }

    public static List<PossibleFinalForm> upElementalMastery(PossibleFinalForm possibleFinalForm){
        return up(possibleFinalForm,elementalMastery,(a,b)->a.setElementalMastery(a.getElementalMastery()+b));
    }

    public static List<PossibleFinalForm> upEnergyRecharge(PossibleFinalForm possibleFinalForm){
        return up(possibleFinalForm,energyRecharge,(a,b)->a.setEnergyRecharge(a.getEnergyRecharge()+b));
    }

    public static List<PossibleFinalForm> upCritRate(PossibleFinalForm possibleFinalForm){
        return up(possibleFinalForm,critRate,(a,b)->a.setCritRate(a.getCritRate()+b));
    }

    public static List<PossibleFinalForm> upCritDamage(PossibleFinalForm possibleFinalForm){
        return up(possibleFinalForm,critDamage,(a,b)->a.setCritDamage(a.getCritDamage()+b));
    }

    public static void setFlatHp(PossibleFinalForm possibleFinalForm,Double value){
        possibleFinalForm.setFlatHP(value);
    }

    public static void setFlatATK(PossibleFinalForm possibleFinalForm,Double value){
        possibleFinalForm.setFlatATK(value);
    }

    public static void setFlatDEF(PossibleFinalForm possibleFinalForm,Double value){
        possibleFinalForm.setFlatDEF(value);
    }

    public static void setPercentHP(PossibleFinalForm possibleFinalForm,Double value){
        possibleFinalForm.setPercentHP(value);
    }

    public static void setPercentATK(PossibleFinalForm possibleFinalForm,Double value){
        possibleFinalForm.setPercentATK(value);
    }

    public static void setPercentDEF(PossibleFinalForm possibleFinalForm,Double value){
        possibleFinalForm.setPercentDEF(value);
    }

    public static void setElementalMastery(PossibleFinalForm possibleFinalForm,Double value){
        possibleFinalForm.setElementalMastery(value);
    }

    public static void setEnergyRecharge(PossibleFinalForm possibleFinalForm,Double value){
        possibleFinalForm.setEnergyRecharge(value);
    }

    public static void setCritRate(PossibleFinalForm possibleFinalForm,Double value){
        possibleFinalForm.setCritRate(value);
    }

    public static void setCritDamage(PossibleFinalForm possibleFinalForm,Double value){
        possibleFinalForm.setCryoDamage(value);
    }
}
